/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_ssap_client_service.h"
#include "sle_ssap_client_hal.h"
#include "sle_hilog.h"
#include "sle_connect_hal.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {

class SleSsapClientService::SleSsapClientServiceCallback {
public:
    SleSsapClientServiceCallback() = default;
    ~SleSsapClientServiceCallback() = default;

    static void OnFindService(
        uint8_t clientId, uint16_t connectId, const ClientFindServiceRes *result, SleHalErrorCode errCode);
    static void OnFindProperty(
        uint8_t clientId, uint16_t connectId, const ClientFindPropertyRes *result, SleHalErrorCode errCode);
    static void OnFindComplete(
        uint8_t clientId, uint16_t connectId, const ClientFindStructureRes *result, SleHalErrorCode errCode);
    static void OnReadResult(
        uint8_t clientId, uint16_t connectId, const ClientHandleValue *value, SleHalErrorCode errCode);
    static void OnReadByUuidComplete(
        uint8_t clientId, uint16_t connectId, const ClientReadByUuidCmpRes *result, SleHalErrorCode errCode);
    static void OnWriteResult(
        uint8_t clientId, uint16_t connectId, const ClientWriteRes *result, SleHalErrorCode errCode);
    static void OnExchangeInfo(
        uint8_t clientId, uint16_t connectId, const SsapMtuInfo *info, SleHalErrorCode errCode);
    static void OnNotification(
        uint8_t clientId, uint16_t connectId, const ClientHandleValue *value, SleHalErrorCode errCode);
    static void OnIndication(
        uint8_t clientId, uint16_t connectId, const ClientHandleValue *value, SleHalErrorCode errCode);
    static SleSsapcHalCallbacks *BuildHalSsapClientCallback();

private:
    static SleSsapcHalCallbacks halCallback_;
};

void SleSsapClientService::SleSsapClientServiceCallback::OnFindService(uint8_t clientId, uint16_t connectId,
    const ClientFindServiceRes *result, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnFindService(clientId, connectId, *result, (SleErrorCode)errCode);
}

void SleSsapClientService::SleSsapClientServiceCallback::OnFindProperty(uint8_t clientId, uint16_t connectId,
    const ClientFindPropertyRes *result, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnFindProperty(clientId, connectId, *result, (SleErrorCode)errCode);
}

void SleSsapClientService::SleSsapClientServiceCallback::OnFindComplete(uint8_t clientId, uint16_t connectId,
    const ClientFindStructureRes *result, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnFindComplete(clientId, connectId, *result, (SleErrorCode)errCode);
}

void SleSsapClientService::SleSsapClientServiceCallback::OnReadResult(uint8_t clientId, uint16_t connectId,
    const ClientHandleValue *value, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnReadResult(clientId, connectId, *value, (SleErrorCode)errCode);
}

void SleSsapClientService::SleSsapClientServiceCallback::OnReadByUuidComplete(uint8_t clientId, uint16_t connectId,
    const ClientReadByUuidCmpRes *result, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnReadByUuidComplete(clientId, connectId, *result, (SleErrorCode)errCode);
}

void SleSsapClientService::SleSsapClientServiceCallback::OnWriteResult(uint8_t clientId, uint16_t connectId,
    const ClientWriteRes *result, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnWriteResult(clientId, connectId, *result, (SleErrorCode)errCode);
}

void SleSsapClientService::SleSsapClientServiceCallback::OnExchangeInfo(uint8_t clientId, uint16_t connectId,
    const SsapMtuInfo *info, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnExchangeInfo(clientId, connectId, *info, (SleErrorCode)errCode);
    SLE_ASSERT_AND_RETURN_LOG(errCode == SLE_HAL_SUCCESS, "ssap client service exchange info status error!");
    uint16_t data_len = info->mtuSize + DATA_LEN_BIGGER;
    SleHalErrorCode ret = SleConnectHalSetDataLength(connectId, data_len);
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "set data buffer length failed!");
}

void SleSsapClientService::SleSsapClientServiceCallback::OnNotification(uint8_t clientId, uint16_t connectId,
    const ClientHandleValue *value, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnNotification(clientId, connectId, *value, (SleErrorCode)errCode);
}

void SleSsapClientService::SleSsapClientServiceCallback::OnIndication(uint8_t clientId, uint16_t connectId,
    const ClientHandleValue *value, SleHalErrorCode errCode)
{
    auto clientService = SleSsapClientService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(clientService, "ssap client service instance null error!");
    SLE_ASSERT_AND_RETURN_LOG(clientService->callback_, "ssap client service callback null error!");
    clientService->callback_->OnNotification(clientId, connectId, *value, (SleErrorCode)errCode);
}

SleSsapcHalCallbacks SleSsapClientService::SleSsapClientServiceCallback::halCallback_;
SleSsapcHalCallbacks *SleSsapClientService::SleSsapClientServiceCallback::BuildHalSsapClientCallback()
{
    SLE_LOGD("BuildHalSsapClientCallback In");
    halCallback_.OnSsapcStructFoundCb = OnFindService;
    halCallback_.OnSsapcPropertyFoundCb = OnFindProperty;
    halCallback_.OnSsapcFindStructDoneCb = OnFindComplete;
    halCallback_.OnSsapcRecvReadRespCb = OnReadResult;
    halCallback_.OnSsapcReadByUuidCb = OnReadByUuidComplete;
    halCallback_.OnSsapcRecvWriteRespCb = OnWriteResult;
    halCallback_.OnSsapcRecvExchangeInfoRespCb = OnExchangeInfo;
    halCallback_.OnSsapcRecvNotificationCb = OnNotification;
    halCallback_.OnSsapcRecvIndicationCb = OnIndication;
    return &halCallback_;
}

SleSsapClientService::SleSsapClientService()
{
    SLE_LOGD("SleSsapClientService In");
    SleHalErrorCode ret = InitSleSsapcHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "init sle ssap client hal failed!");
    serviceCallback_ = std::make_unique<SleSsapClientServiceCallback>();
    SLE_ASSERT_AND_RETURN_LOG(serviceCallback_, "create service callback ptr failed!");
    ret = SleSsapcHalRegisterCallbacks(serviceCallback_->BuildHalSsapClientCallback());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "register hal ssap client callback failed!");
}

SleSsapClientService::~SleSsapClientService()
{
    SLE_LOGD("~SleSsapClientService In");
    SleHalErrorCode ret = DeinitSleSsapcHal();
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "deinit sle ssap client hal failed!");
    serviceCallback_ = nullptr;
}

SleSsapClientService *SleSsapClientService::GetInstance()
{
    static SleSsapClientService instance;
    return &instance;
}

SleErrorCode SleSsapClientService:: RegisterSsapClient(const Uuid &uuid, uint8_t &clientId)
{
    SLE_LOGD("RegisterSsapClient In");
    SleUuid appUuid = uuid.ConvertToSleUuid();
    SleHalErrorCode ret = SleSsapcHalAddClient(&appUuid, &clientId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "register ssap client failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: UnregisterSsapClient(uint8_t clientId)
{
    SLE_LOGD("UnregisterSsapClient In");
    SleHalErrorCode ret = SleSsapcHalRemoveClient(clientId);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "unregister ssap client failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: FindSsapStructure(
    uint8_t clientId, uint16_t connectId, const SsapClientFindStructure &param)
{
    SLE_LOGD("RegisterSsapClient In");
    ClientFindStructure structure;
    param.ConvertToClientFindStructure(structure);
    SleHalErrorCode ret = SleSsapcHalFindStructure(clientId, connectId, &structure);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "find ssap structure failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: ReadRequestByUuid(
    uint8_t clientId, uint16_t connectId, const SsapClientReadReqByUUID &param)
{
    SLE_LOGD("ReadRequestByUuid In");
    ClientReadReqByUUID params;
    param.ConvertToClientReadReqByUUID(params);
    SleHalErrorCode ret = SleSsapcHalReadReqByUuid(clientId, connectId, &params);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "read request by uuid failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: ReadRequest(uint8_t clientId, uint16_t connectId, uint16_t handle, uint8_t type)
{
    SLE_LOGD("ReadRequest In");
    SleHalErrorCode ret = SleSsapcHalReadReq(clientId, connectId, handle, (SleSsapPropertyType)type);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "read request failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: WriteRequest(
    uint8_t clientId, uint16_t connectId, const SsapClientHandleValue &value)
{
#if 0
    SLE_LOGD("WriteRequest In");
#endif
    ClientWriteParam params;
    value.ConvertToClientWriteParam(params);
    SleHalErrorCode ret = SleSsapcHalWriteReq(clientId, connectId, &params);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "write request failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: WriteCommand(
    uint8_t clientId, uint16_t connectId, const SsapClientHandleValue &value)
{
#if 0
    SLE_LOGD("WriteCommand In");
#endif
    ClientWriteParam params;
    value.ConvertToClientWriteParam(params);
    SleHalErrorCode ret = SleSsapcHalWriteCmd(clientId, connectId, &params);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "write command failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: ExchangeInfo(
    uint8_t clientId, uint16_t connectId, uint32_t mtu, uint16_t version)
{
    SLE_LOGD("ExchangeInfo In");
    SsapMtuInfo info = {
        .mtuSize = mtu,
        .version = version,
    };
    SleHalErrorCode ret = SleSsapcHalExchangeInfoReq(clientId, connectId, &info);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, SLE_ERR_FAILED, "exchange info failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: RegisterSsapClientCallback(ISsapClientCallback &callback)
{
    SLE_LOGD("RegisterSsapClientCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback_ != &callback, SLE_ERR_INVALID_PARAM, "callback already registered error!");
    callback_ = &callback;
    return SLE_NO_ERROR;
}

SleErrorCode SleSsapClientService:: UnregisterSsapClientCallback(ISsapClientCallback &callback)
{
    SLE_LOGD("UnregisterSsapClientCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback_ == &callback, SLE_ERR_INVALID_PARAM, "callback already unregistered error!");
    callback_ = nullptr;
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS